//---------------------------------------------------------------------
//  This file is part of the Background Motion solution.
// 
//  Copyright (C) Mindscape (TM).  All rights reserved.
//  http://www.mindscape.co.nz
// 
//  THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//  PARTICULAR PURPOSE.
//---------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Mindscape.BackgroundMotion.Services.Contracts;
using Mindscape.BackgroundMotion.Services.Contracts.Entities;
using System.Collections;

namespace Mindscape.BackgroundMotion.GadgetServices
{
  /// <summary>
  /// Provides a COM visible interface for allowing consumers to make secure and authenticated calls to the Background Motion content services
  /// </summary>
  [Guid("31337f69-7e06-4f39-a8f2-db6d6b7d5077")]
  [ProgId("BackgroundMotionGadgetServices.ContentServiceClient")]
  [ClassInterface(ClassInterfaceType.None)]
  [ComVisible(true)]
  public class ContentServiceClient
  {
    private ChannelFactory<IContentService> _factory;
    private IContentService _service;
    private string _address;

    /// <summary>
    /// The address of the service endpoint
    /// </summary>
    /// <remarks>
    /// This property takes care of the wire-up and instantiation of the service factory
    /// Based on the values set on other properties such as IsSecure, RequiresAuthentication, Username and Password the factory
    /// will be set up for a WSHttpBinding
    /// </remarks>
    public string Address
    {
      get 
      {
        return _address;
      }
      set 
      {
        EndpointAddress endpoint = new EndpointAddress(value);
        Binding binding = IsSecure ? new WSHttpBinding() as Binding : new BasicHttpBinding() as Binding;

        if (IsSecure && RequiresAuthentication)
        {
          WSHttpBinding secureBinding = binding as WSHttpBinding;
          if (secureBinding != null)
          {
            secureBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
          }
        }

        _address = value;        
        _factory = new ChannelFactory<IContentService>(binding, endpoint);
        _service = null;

        if (IsSecure && RequiresAuthentication)
        {
          _factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
          _factory.Credentials.UserName.UserName = Username;
          _factory.Credentials.UserName.Password = Password;
        }
      }
    }

    /// <summary>
    /// Indicates that the endpoint is expected to be secure - this implies message level security
    /// </summary>
    /// <seealso cref="Address"/>
    public bool IsSecure;

    /// <summary>
    /// Indicates that the endpoint requires credentials to be supplied for the endpoint
    /// </summary>
    /// <seealso cref="Address"/>
    public bool RequiresAuthentication;

    /// <summary>
    /// The username to be used for authentication with the endpoint
    /// </summary>
    /// <seealso cref="Address"/>
    public string Username;

    /// <summary>
    /// The password to be used for authentication with the endpoint
    /// </summary>
    /// <seealso cref="Address"/>
    public string Password;

    /// <summary>
    /// 
    /// </summary>
    /// <exception cref="ArgumentException">Thrown if the Address property has not been set which indicates that the service factory has not been initialized</exception>
    public IContentService ContentService
    {
      get 
      {
        if (string.IsNullOrEmpty(Address) || _factory == null) throw new ArgumentException("Address has not been set");
        
        if (_service == null)
        {
          _service = _factory.CreateChannel();
        }

        return _service;
      }
    }

    /// <summary>
    /// Returns a COM Visible Content item which corresponds to the requested id
    /// </summary>
    /// <param name="id">The unique identifier for the </param>
    /// <returns>A COM Visible Content item</returns>
    public ComVisibleContent GetContent(int id)
    {
      return new ComVisibleContent(ContentService.GetContent(id));
    }

    /// <summary>
    /// Gets the content currently pending moderation
    /// </summary>
    /// <returns>A collection of COM Visible Content items</returns>
    public ComVisibleContentCollection GetContentForModeration()
    {
      ComVisibleContentCollection collection = new ComVisibleContentCollection();

      foreach (Content item in ContentService.GetContentForModeration())
      {
        collection.Add(new ComVisibleContent(item));
      }

      return collection;
    }

    /// <summary>
    /// Approves the specified content item.
    /// </summary>
    /// <param name="id">The id of the content item which is to be approved.</param>
    public void ApproveContent(int id)
    {
      ContentService.ApproveContent(id);
    }
  }

  /// <summary>
  /// Represents a item of Content in BackgroundMotion
  /// </summary>
  /// <remarks>
  /// This class wraps the Content class which is returned from a web service call
  /// </remarks>
  [Guid("31337f69-7e06-4f39-a8f2-db6d6b7d5078")]
  [ProgId("BackgroundMotionGadgetServices.Content")]
  [ClassInterface(ClassInterfaceType.None)]
  [ComVisible(true)]
  public class ComVisibleContent
  {
    public ComVisibleContent()
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="ComVisibleContent"/> class.
    /// </summary>
    /// <param name="content">The content item which will be contained within this item.</param>
    public ComVisibleContent(Content content)
    {
      Id = content.Id;
      Title = content.Title;
      Description = content.Description;
      PreviewImage = content.PreviewImage;
    }

    public int Id;
    public string Title;
    public string Description;
    public string PreviewImage;
  }

  /// <summary>
  /// Represents a collection of Content items
  /// </summary>
  [Guid("31337f69-7e06-4f39-a8f2-db6d6b7d5079")]
  [ProgId("BackgroundMotionGadgetServices.ContentCollection")]
  [ClassInterface(ClassInterfaceType.None)]
  [ComVisible(true)]
  public class ComVisibleContentCollection
  {
    private List<ComVisibleContent> _content;

        /// <summary>
        /// Initializes a new instance of the <see cref="ComVisibleContentCollection"/> class.
        /// </summary>
        public ComVisibleContentCollection()
        {
            _content = new List<ComVisibleContent>();
        }

        /// <summary>
        /// Gets the <see cref="Mindscape.BackgroundMotion.GadgetServices.ComVisibleContent"/> at the specified index.
        /// </summary>
        /// <value></value>
        public ComVisibleContent this[int index] 
        {
            get
            {
                return _content[index];
            }
        }

        /// <summary>
        /// Gets the requested item.
        /// </summary>
        /// <param name="index">The index of the item to be returned.</param>
        /// <returns></returns>
        public ComVisibleContent GetItem(int index)
        {
            return _content[index];
        }

        #region ICollection Members

        public void CopyTo(Array array, int index)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        /// <summary>
        /// Gets the count of the collection
        /// </summary>
        public int Count
        {
            get { return _content.Count; }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is synchronized.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is synchronized; otherwise, <c>false</c>.
        /// </value>
        public bool IsSynchronized
        {
            get { return true; }
        }

        /// <summary>
        /// Gets the sync root.
        /// </summary>
        /// <value>The sync root.</value>
        public object SyncRoot
        {
            get { return null; }
        }

        #endregion

        /// <summary>
        /// Adds an item into the collection
        /// </summary>
        public void Add( ComVisibleContent item )
        {
            _content.Add(item);
        }

        #region IEnumerable Members

        /// <summary>
        /// Gets the enumerator for iterating through the collection
        /// </summary>
        public IEnumerator GetEnumerator()
        {
            foreach (ComVisibleContent item in _content)
                yield return item;
        }

        #endregion
  }
}
